package org.zkoss.zktc.core.groovy;

import groovy.lang.Binding;
import groovy.lang.GroovyRuntimeException;
import groovy.lang.GroovyShell;
import groovy.util.GroovyScriptEngine;
import groovy.util.ResourceConnector;
import groovy.util.ResourceException;

import java.io.File;
import java.io.IOException;
import java.io.Reader;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Logger;

import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.MultipleCompilationErrorsException;
import org.zkoss.zktc.core.util.Files;

public class Engine {

//	private static final String[] groovys = {"WidgetDriverScriptBase"};
//	private static Logger logger = Logger.getLogger(Runner.class.getName()); 
	
//	private volatile static Engine instance;
	
//	GroovyScriptEngine engine;
	GroovyShell shell;
	CompilerConfiguration compiler;
	Binding binding;
	
	final static String globalImport;
	static{
		StringBuilder sb = new StringBuilder();
		sb.append("import org.zkoss.zktc.core.groovy.*;");
		sb.append("import org.zkoss.zktc.core.widget.*;");
		globalImport = sb.toString();
	}
	
	
	public Engine(Binding binding){
		init(binding);
	}
	
	private void init(Binding binding) {
		this.binding = binding;
//		GroovyScriptEngine engine = new GroovyScriptEngine(new ResourceConnector() {
//			public URLConnection getResourceConnection(String name)
//					throws ResourceException {
//				String p = name+".groovy";
//				URL url = Engine.class.getResource(p);
//				if(url!=null){
//					try {
//						return url.openConnection();
//					} catch (IOException e) {
//						throw new ResourceException(name + " not found by path "+p,e);
//					}
//				}
//				throw new ResourceException(name + " not found by path "+p);
//			}
//		},getCurrentLoader());
////		
//		try {
//			for(String nm:groovys){
//				engine.loadScriptByName(nm);
//			}
//		} catch (Exception e) {
//			throw new RuntimeException("could not initial Engine",e);
//		}
		
		compiler = new CompilerConfiguration();
		compiler.setScriptBaseClass(Engine.class.getPackage().getName()+".WidgetDriverScriptBase");
		shell = new GroovyShell(/*engine.getGroovyClassLoader(),*/binding,compiler);
		
	}
	
	
	private ClassLoader getCurrentLoader(){
		ClassLoader cl = Thread.currentThread().getContextClassLoader();
		return cl==null?getClass().getClassLoader():cl;
	}

//	public static Engine instance(){
//		if(instance==null){
//			synchronized(Engine.class){
//				if(instance==null){
//					instance = new Engine();
//				}
//			}
//		}
//		return instance;
//	}
	
	
	public Object execute(Reader reader) throws ExecutionException{
//		return execute(reader, new Binding());
//	}
//	public Object execute(Reader reader, Binding binding) throws ExecutionException{
		try {
			return execute(Files.readAll(reader).toString());
		} catch (IOException e) {
			throw new ExecutionException(e.getMessage(),e);
		}
	}
	
//	public Object execute(String script) throws ExecutionException{
//		return execute(script, new Binding());
//	}
	public Object execute(String script/*, Binding binding*/) throws ExecutionException{
		if(script==null){
			throw new IllegalArgumentException("script is null");
		}
		try{
//		
//		if(!binding.getVariables().containsKey(Context.NAME)){
//			binding.setVariable(Context.NAME, null);//to prevent variable not found
//		}
			
//		System.out.println(">>>>>>>>>>"+binding+">>"+binding.getVariables());
//			GroovyShell shell = new GroovyShell(binding,compiler);
			StringBuilder sb = new StringBuilder();
			sb.append(globalImport);
			sb.append(script);
			Object value = shell.evaluate(sb.toString());
//		System.out.println(">>>>>>>>>>>>"+binding.getVariables());
			return value;
		}catch(java.lang.AssertionError e){
			throw new ExecutionException(e.getMessage(),e);
		}catch(Exception e){
			throw new ExecutionException(e.getMessage(),e);
		}
	}

	public Binding getBinding() {
		return binding;
	}
}
